﻿#include <iostream>
using namespace std;

//类里面成员函数我们什么都不写的时候，编译器会自动生成6个函数，这6个函数就叫默认（缺省）成员函数

//1、构造函数--》对象的初始化
//class Date
//{
//public:
//	//c语言中的初始化函数，我们可能会忘记调用它
//	//C++为了解决这个问题，引入构造函数，来初始化
//	//void Init(int year, int month, int day)
//	//{
//	//	_year = year;
//	//	_month = month;
//	//	_day = day;
//	//}
//	//构造函数-》对象实例化的时候调用，这样就保证对象一定初始化
//	//Date(int year, int month, int day)
//	//{
//	//	_year = year;
//	//	_month = month;
//	//	_day = day;
//	//}
//	
//
//	//一般情况，对象初始化惯例都分两种，默认值初始化，给定值初始化。
//	//合二为一，给一个全缺省的，这样定义的构造函数写一个就ok。
//	Date(int year = 0, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//private:
//	int _year;
//	int _month;
//	int _day;
//	
//};
////
////class Stack
////{
////public:
////	void Init()
////	{
////		_a = nullptr;
////		_size = _capacity = 0;
////	}
////
////	Stack()
////	{
////		_a = nullptr;
////		_size = _capacity = 0;
////	}
////
////	Stack(int capacity)
////	{
////		_a = (int*)malloc(sizeof(int) * capacity);
////		_size = 0;
////		_capacity = capacity;
////	}
////
////	
////private:
////	int* _a;
////	int _size;
////	int _capacity;
////
////};
////int main()
////{
////	Date d1(2021,5,24);
////	d1.Print();
////
////	Date d2;
////	d2.Print();
////
////	Date d3(2021);
////	d3.Print();
////
////	return 0;
////}
//
//class A
//{
//public:
//	A(int a = 0)
//	{
//		cout << "S=A(int a=0)构造函数" << endl;
//		_a = a;
//	}
//	void Print()
//	{
//		cout << _a << endl;
//	}
//private:
//	int _a;
//};
//
//class Data
//{
//public:
//	//我们不写，编译器会自动生成一个构造函数，我们写了，编译器就不会生成了，所以说构造函数叫默认成员函数。
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//		_aa.Print();
//	}
//private:
//	int _year;
//	int _month;
//	int _day;
//
//	A _aa;
//};
//
////默认构造函数 很多同学都会以为是我们不写，编译器默认生成的那一个，这个解释是不全面的
////1、我们不写，编译器默认生成的
////2、我们自己写的无参数
////3、我们写的全缺省
////总结一下：不用参数就可以调用的构造函数
//int main()
//{
//	Date d2;
//	d2.Print();
//	return 0;
//}
//
//
//class Date
//{
//public:
//	Date(int year, int month, int day)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//	//析构函数
//	~Date()
//	{
//		//资源的清理 
//		cout << "~Date()" << endl;
//	}
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//
//class Stack
//{
//public:
//	Stack(int capacity = 4)
//	{
//		_a = (int*)malloc(sizeof(int) * capacity);
//		_size = 0;
//		_capacity = capacity;
//	}
//	void Push(int x)
//	{}
//	//像Stack这样的类，析构函数具有重大意义
//	~Stack()
//	{
//		cout << "~Stack()析构函数" << endl;
//		//资源清理
//		free(_a);
//		_a = nullptr;
//		_size = _capacity = 0;
//	}
//private:
//	int* _a;
//	int _size;
//	int _capacity;
//};
//
//int main()
//{
//	
//	Stack st1;
//	st1.Push(1);
//	st1.Push(2);
//	st1.Push(3);
//
//	Stack st2;
////	st2.Push(10);
////	st2.Push(11);
////	st2.Push(12);
////	return 0;
////}
//
//class Date
//{
//public:
//	Date(int year, int month, int day)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//	bool Equel(Date d)
//	{
//		return _year == d._year
//			&& _month == d._month
//			&& _day == d._day;
//	}
//	bool operator==(Date x)
//	{
//		return _year == x._year
//			&& _month == x._month
//			&& _day == x._day;
//	}
//	//当运算符是两个操作数时，第一个参数时左操作数，第二个参数是又操作数
//	//d1<d2
//	bool operator<(Date x)
//	{
//		if (_year < x._year)
//		{
//			return true;
//		}
//		else if (_year == x._year)
//		{
//			if (_month < x._month)
//			{
//				return true;
//			}
//			else if (_month == x._month)
//			{
//				if (_day < x._day)
//				{
//					return true;
//				}
//			}
//		}
//		
//		return false;
//	}
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//
//class Array
//{
//public:
//	Array()
//	{
//		for (int i = 0; i < 10; i++)
//		{
//			_a[i] = i * 10;
//		}
//	}
//	int& operator[](size_t pos)
//	{
//		return _a[pos];
//	}
//private:
//	int _a[10];
//};
//
//int main()
//{
//	Date d1(2021, 1, 5);
//	Date d2(2021, 1, 6);
//
//	//内置类型，语言层面就支持运算符
//	//自定义类型，默认不支持。C++可以用运算符重载来让类对象支持某个运算符
//	//d1.operator==(d2);//d1.operator==(&d1,d2);
//	cout << (d1 == d2) << endl;
//	cout << (d1 < d2) << endl;
//
//	Array ay;
//	cout << ay[0] << endl;
//	cout << ay[1] << endl;
//	cout << ay[2] << endl;
//	cout << ay[3] << endl;
//	cout << ay[4] << endl;
//
//	//修改--赋值给了返回对象的引用
//	ay[0] = 100;
//	ay[1] = 200;
//	ay[2] = 300;
//	ay[3] = 400;
//
//	cout << ay[0] << endl;
//	cout << ay[1] << endl;
//	cout << ay[2] << endl;
//	cout << ay[3] << endl;
//	cout << ay[4] << endl;
//
//	return 0;
//}


////// 1、功能
////// 2、特性及用法
////// 3、编译器不写默认生成的做了啥

////6个默认成员函数
////—我们不写，编译器会默认生成，虽然会自动生成，但是好多时候还是需要我们自己写因为生成的那个不一定好用。
//// a、构造函数--初始化，大部分情况下，都需要我们自己写构造函数
//// b、析构函数--清理对象中的资源
//// c、拷贝构造函数--拷贝初始化，特殊构造函数  深浅拷贝问题
//// d、赋值运算符重载--也是拷贝行为，但不一样的是，拷贝构造是创建一个对象时，拿同类对象初始化的拷贝
/////针对我们不写编译默认生成的总结一下：
//// 构造和析构的特性是类似，我们不写编译器内置类型不处理，自定义类型调用它的构造和析构处理
//// 拷贝构造和赋值重载特性是类似的，内置类型会完成浅拷贝，自定义类型会调用他们的拷贝构造和赋值重载

class A
{
public:
	A(int a = 1)
	{
		_a = a;
	}

	A(const A& a)
	{
		cout << "A(const A& a)" << endl;
		_a = a._a;
	}

	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	// Date d4(d1);
	Date(const Date& d)
	{
		/*d._year = _year;
		d._month = _month;
		d._day = _day;*/

		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 默认成员函数，我们不写编译器会自动生成拷贝构造
	// 这个拷贝构造对内置类型会完成浅拷贝，或者值拷贝
	// d1 < d2 -> d1.operator<(&d1, d2)
	// bool operator<(const Date& d2); -> bool operator<(Date* this, const Date& d2);

	// d1 = d2;  d1.operator=(&d1, d2)
	// d1 = d1;
	// 赋值运算符的也是一个默认成员函数，也就是说我们不写编译器会自动生成一个
	// 编译器默认生成赋值运算符跟拷贝构造的特性是一致的
	// a、针对内置类型，会完浅拷贝，也就是说像Date这样的类不需要我们自己写赋值运算符重载，Stack就得自己写
	// b、针对自定义类型，也一样，它会调用他的赋值运算符重载完成拷贝
	Date& operator=(const Date& d) // void operator=(Date* this, const Date& d)
	{
		if (this != &d) // 检查如果不是自己给自己赋值，才需要拷贝
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
	
		return *this;
	}

	void Print()
	{
		cout << _year << "-" << _month <<"-" << _day << endl;
	}

	// 析构函数，我们不需要写，编译默认生成就够用，对象内没有资源清理
	// 默认生成的析构函函数也是基本不做什么事情，release下优化，就没了
private:
	int _year;
	int _month;
	int _day;

	//A _aa;
};

class Stack
{
public:
	Stack(int capacity = 4)
	{
		if (capacity <= 0)
		{
			_a = nullptr;
			_size = _capacity = 0;
		}
		else
		{
			_a = (int*)malloc(sizeof(int)*capacity);
			_capacity = capacity;
			_size = 0;
		}
	}

	~Stack()
	{
		free(_a);
		_size = _capacity = 0;
		_a = nullptr;
	}

private:
	int* _a;
	int _size;
	int _capacity;
};

int main()
{
	//Stack st;
	//Stack copy(st);

	//Date d1(2020, 5, 26);
	//Date d2;
	////Date d3(); // 没有调到构造函数，对象没有被构造出来
	////Date f1();
	//d1.Print();
	//d2.Print();
	////d3.Print();

	//Date d4(d1); // 拷贝构造函数
	//d4.Print();
	//d1.Print();

	/*Date d1(2020, 5, 26);
	f1(d1);
	f2(d1);*/

	Date d1(2020, 5, 26);
	Date d2;
	Date d3(2020, 1, 1);
	d1.Print();
	d2.Print();

	// 也是拷贝行为，但是不一样的是，拷贝构造是创建一个对象时，拿同类对象初始化的拷贝
	// 这里的复制拷贝时连个对象已经都存在了，都被初始化过了，现在想把一个对象，复制拷贝给另一个对象
	d1 = d2;
	d1.Print();
	d2.Print();

	// 连续赋值
	d1 = d2 = d3;
	// i = j = k;
	d1 = d1;

	Date d5(d1); // 拷贝构造  拿一个已经存在的对象去构造初始化另一个要创建的对象
	d1 = d2;     // 赋值重载  两个已经存在的对象-》拷贝
	Date d6 = d1; // 拷贝构造? 赋值重载?


	return 0;
}